package com.chenliang.invoke.utils;


import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.Map;
import static org.springframework.http.HttpMethod.*;

/**
 * @program: long_invoke
 * @description:
 * @author: liangchen23
 * @create: 2022-03-16 09:41
 */
@Slf4j
public class HttpClientUtils {


    /**
     * 携带请求头不携带get参数的get方法
     *
     * @param url
     * @param headerMap
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T doGetWithHeader(String url, Map<String, String> headerMap, Class<T> clazz) {
        return get(url, headerMap, new HashMap<>(), clazz);

    }

    /**
     * 携带请求头携带get参数的get方法
     *
     * @param url
     * @param headerMap
     * @param paramMap
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T doGetWithHeader(String url, Map<String, String> headerMap, Map<String, String> paramMap, Class<T> clazz) {
        return get(url, headerMap, paramMap, clazz);
    }

    /**
     * 不携带请求头不携带get参数的get方法
     *
     * @param url
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T doGet(String url, Class<T> clazz) {
        return get(url, new HashMap<>(), new HashMap<>(), clazz);

    }

    /**
     * 不携带请求头携带get参数的get方法
     *
     * @param url
     * @param paramMap
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T doGet(String url, Map<String, String> paramMap, Class<T> clazz) {
        return get(url, new HashMap<>(), paramMap, clazz);

    }

    private static <T> T get(String url, Map<String, String> headerMap, Map<String, String> paramMap, Class<T> clazz) {
        if (!paramMap.isEmpty()) {
            StringBuilder urlBuilder = new StringBuilder(url);
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                String name = entry.getKey();
                urlBuilder.append("?").append(name).append("={").append(name).append("}");
            }
            url = urlBuilder.toString();
        }
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);

        if (!headerMap.isEmpty()) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                headers.add(entry.getKey(), entry.getValue());
            }
        }


        RestTemplate restTemplate = new RestTemplate();
        HttpEntity<String> entity = new HttpEntity<>(null, headers);

        ResponseEntity<T> responseEntity = null;

        try {
            responseEntity = restTemplate.exchange(url, GET, entity, clazz, paramMap);
        } catch (HttpClientErrorException e) {
            log.error("url={},request={}请求出错", url, entity);
        }
        if (responseEntity == null) {
            return null;
        }
        return responseEntity.getBody();

    }


    /**
     * 携带header的json post请求
     *
     * @param <T>
     * @param url
     * @param headerMap
     * @param requestJson
     * @param clazz
     * @return
     */
    public static <T> T doPostJsonWithHeader(String url, Map<String, String> headerMap, String requestJson, Class<T> clazz) {
        return postJson(url, headerMap, requestJson, clazz);
    }

    /**
     * 不携带header的json post请求
     *
     * @param url
     * @param requestJson
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T doPostJson(String url, String requestJson, Class<T> clazz) {
        return postJson(url, new HashMap<>(), requestJson, clazz);
    }


    /**
     * post请求
     * <p>
     * json类型
     *
     * @param url
     * @param headerMap
     * @param requestJson
     * @param clazz
     * @param <T>
     * @return
     */
    private static <T> T postJson(String url, Map<String, String> headerMap, String requestJson, Class<T> clazz) {

        //        //采用绕过验证的方式处理https请求
//        SSLContext sslContext = createIgnoreVerifySSL();
//
//        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
//
//        CloseableHttpClient httpClient = HttpClients.custom()
//                .setSSLSocketFactory(csf)
//                .build();
//
//        HttpComponentsClientHttpRequestFactory requestFactory =
//                new HttpComponentsClientHttpRequestFactory();
//
//        requestFactory.setHttpClient(httpClient);
//
//        RestTemplate restTemplate = new RestTemplate(requestFactory);

        RestTemplate restTemplate = new RestTemplate();
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        // 设置请求类型为json
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        if (!headerMap.isEmpty()) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                headers.add(entry.getKey(), entry.getValue());
            }
        }

        HttpEntity<String> entity = new HttpEntity<>(requestJson, headers);

        ResponseEntity<T> responseEntity = null;

        try {
            responseEntity = restTemplate.postForEntity(url, entity, clazz);
        } catch (HttpClientErrorException e) {
            log.error("url={},request={}请求出错", url, entity);
        }
        if (responseEntity == null) {
            return null;
        }
        return responseEntity.getBody();

    }

    /**
     * 表单提交post请求
     * <p>
     * 响应正常时，返回对象，否则返回null
     *
     * @param url      url
     * @param paramMap 表单参数
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T doPostForm(String url, MultiValueMap<String, String> paramMap, Class<T> clazz) {
        return postForm(url, new HashMap<>(), paramMap, clazz);
    }

    /**
     * 表单提交并携带header
     *
     * @param url
     * @param headerMap
     * @param paramMap
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T doPostFormWithHeader(String url,
                                             Map<String, String> headerMap,
                                             MultiValueMap<String, String> paramMap,
                                             Class<T> clazz) {
        return postForm(url, headerMap, paramMap, clazz);

    }

    /**
     * 表单提交
     *
     * @param url
     * @param headerMap
     * @param paramMap
     * @param clazz
     * @param <T>
     * @return
     */
    private static <T> T postForm(String url,
                                  Map<String, String> headerMap,
                                  MultiValueMap<String, String> paramMap,
                                  Class<T> clazz) {

        RestTemplate restTemplate = new RestTemplate();

        // 设置请求头为表单
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        if (!headerMap.isEmpty()) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                headers.add(entry.getKey(), entry.getValue());
            }
        }

        // 构造请求体
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(paramMap, headers);
//        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>( headers);


        ResponseEntity<T> response = null;
        try {
            response = restTemplate.postForEntity(url, request, clazz);
        } catch (HttpClientErrorException e) {
            log.error("url={},request={}请求出错", url, request);
        }
        if (response == null) {
            return null;
        }
        return response.getBody();

    }


    /**
     * 绕过验证
     *
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sc = SSLContext.getInstance("SSLv3");

        // 实现一个X509TrustManager接口，用于绕过验证，不用修改里面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sc.init(null, new TrustManager[]{trustManager}, null);
        return sc;
    }
}
